use std::collections::HashMap;
use std::error::Error;
use std::sync::{Arc, RwLock};

pub struct InstanceMgr<T>(RwLock<HashMap<String, Option<Arc<RwLock<T>>>>>);
impl<T> InstanceMgr<T> {
    pub fn new() -> Self {
        InstanceMgr(RwLock::new(HashMap::new()))
    }

    /// 获取保存的项
    pub fn get(&self, key: &String) -> Option<Arc<RwLock<T>>> {
        let reader = self.0.read().unwrap();
        let result = reader.get(key);
        match result {
            Some(val) => val.clone(),
            None => None,
        }
    }

    /// 获取，如果不存在，则通过函数获取
    pub fn get_or_set<TErr: Error>(
        &self,
        key: &String,
        init_fn: impl Fn() -> Result<Option<T>, TErr>,
    ) -> Result<Option<Arc<RwLock<T>>>, TErr> {
        let result = self.get(key);
        if result.is_some() {
            return Ok(result);
        }

        let result = init_fn();
        match result {
            Ok(val) => {
                if val.is_some() {
                    let set_val = Arc::new(RwLock::new(val.unwrap()));
                    let return_val = set_val.clone();

                    let mut map_val = self.0.write().unwrap();
                    map_val.insert(key.clone(), Some(set_val));

                    Ok(Some(return_val))
                } else {
                    Ok(None)
                }
            }
            Err(val) => Err(val),
        }
    }

    /// 获取项，并进行更新
    pub fn get_and_update(&self, key: &String, fn_obj: impl Fn(&mut T) -> bool) {
        let val = self.get(key);
        let mut actual_val = val.as_ref().unwrap().write().unwrap();
        fn_obj(&mut *actual_val);
    }

    /// 设置保存的项
    pub fn set(&self, key: &String, val: T) -> Arc<RwLock<T>> {
        {
            let mut map_val = self.0.write().unwrap();
            {
                let old_val = map_val.get(key);
                match old_val {
                    Some(tmp_val) => {
                        *tmp_val.as_ref().unwrap().write().unwrap() = val;
                        return map_val.get(key).unwrap().as_ref().unwrap().clone();
                    }
                    None => {}
                }
            }

            map_val.insert(key.clone(), Some(Arc::new(RwLock::new(val))));
        }

        self.get(key).unwrap()
    }

    /// 移除项
    pub fn remove(&self, key: &String) -> Option<Value<T>> {
        let result = self.0.write().unwrap().remove(key);
        match result {
            Some(val) => val,
            None => None,
        }
    }
}

impl<T> Default for InstanceMgr<T> {
    fn default() -> Self {
        InstanceMgr::new()
    }
}

pub type Value<T> = Arc<RwLock<T>>;
